
import { Backtest } from "../lib/quant/Backtest";
import { FuturesBacktest } from "../lib/quant/FuturesBacktest";
import { RiskModel } from "./RiskModel";
import { MergeData } from "./DataHandler";
import { TradingStrategy, defaultStrategy } from "./TradingStrategy";
import { MixIndicatorsTolerance } from './types'

interface StrategyBacktestOptions {
  mixIndicatorsTolerance?: MixIndicatorsTolerance
  symbol: string
  code?: string
}
export class StrategyBacktest {
  private tradingStrategy = new TradingStrategy({tradeFrequencyLimit: 0, isMock: true});
  backtestMap: Record<string, Backtest> = {}
  futuresBacktestMap: Record<string, FuturesBacktest> = {}
  options: StrategyBacktestOptions

  constructor(options: StrategyBacktestOptions) {
    // this.init()
    this.options = options
  }
  
  init(symbol: string) {
    if (this.backtestMap[symbol]) {
      return;
    }

    this.backtestMap[symbol] = new Backtest({
      balance: 3600,
      volume: 0,
      tradeVolume: (price) => 1000 / price,
    });

    this.futuresBacktestMap[symbol] = new FuturesBacktest({
      accountValue: 4200,
      leverage: 1,
      makerFee: 0.00025,
      takerFee: 0.00075,
    });
    const futuresriskModel = new RiskModel()
    futuresriskModel.updateConfig(symbol, { stopLoss: 0.5, stopProfit: 0.99, positionLimit: 0.9, minLongTradeQuantity: 0.2, minShortTradeQuantity: 0.2 })
    const trainType = 'spot' as 'spot' | 'futures'

    this.tradingStrategy
    .addCustomStrategy('test', this.options.symbol, {
      code: this.options.code ? this.options.code : defaultStrategy({mode: 0, mixIndicatorsTolerance: this.options.mixIndicatorsTolerance}),
    })
    .onSignal((signal, bar) => {
      const tradeData = {
        symbol: symbol,
        timestamp: bar.timestamp,
        close: bar.close,
        low: bar.low,
        high: bar.high,
        open: bar.open,
        volume: bar.volume,
        sell: bar.sell,
        buy: bar.buy,
        action: undefined,
        label_text: ''
      }

      if (trainType === 'spot') {
        tradeData.action = signal
        this.backtestMap[symbol].mockTrade({ 
          close: bar.close,
          action: signal,
          timestamp: bar.timestamp,
        })
      
      } else {
        this.futuresBacktestMap[symbol].mockTrade({
            price: bar.close,
            side: undefined,
            positionSide: undefined,
            time: bar.timestamp,
            volume: 0,
            text: ''
        });
      }
    });
    

    this.tradingStrategy.onMixIndicator((bar, mixIndicator) => {
      if (trainType === 'spot') {
        this.backtestMap[symbol].mockTrade({ 
          close: bar.close,
          action: undefined,
          timestamp: bar.timestamp,
          volume: 0,
        })
      } else {
        this.futuresBacktestMap[symbol].mockTrade({
            price: bar.close,
            side: undefined,
            positionSide: undefined,
            time: bar.timestamp,
            volume: 0,
            text: ''
        });
      }
      // const positionInfo = this.futuresBacktestMap[symbol].getAccountInfo();
      // futuresriskModel.updateFuturesBalance();
      // futuresriskModel.updatePositions();
      // futuresriskModel.updatePositionsPrice();
    });
    futuresriskModel.on('order', ({quantity, side,positionSide, markPrice, type}) => {
      if (trainType === 'spot') {
        return
      }
      this.futuresBacktestMap[symbol].mockTrade({
        price: markPrice,
        side: side,
        positionSide: positionSide,
        time: Date.now(),
        volume: quantity,
      });
    });
  }

  addData(data: MergeData, period:  "15m" | "4h" | "1d") {
    const symbol = data.symbol;
    this.init(symbol);
    this.tradingStrategy.push(data, period);
  }
  updateData(data: MergeData, period:  "15m" | "4h" | "1d") {
    const symbol = data.symbol;
    this.init(symbol);
    this.tradingStrategy.update(data, period);
  }
  getResult(symbol: string) {
    return this.backtestMap[symbol].getResult();
  }
  getTrades(symbol: string) {
    return this.backtestMap[symbol]?.getTrades();
  }

  getFuturesResult(symbol: string) {
    return this.futuresBacktestMap[symbol].getResult();
  }
  getFuturesTrades(symbol: string) {
    return this.futuresBacktestMap[symbol]?.getTrades();
  }
  destroyed() {
    this.tradingStrategy.destroy();
    this.backtestMap = null;
    this.futuresBacktestMap = null;
  }
}